#include "chequeform_touch.h"

#include <QKeyEvent>
#include <QLabel>
#include <QSqlQuery>
#include <QSqlError>
#include <QPushButton>
#include <QHeaderView>
#include <QDate>
#include <QModelIndex>
#include <QScreen>
#include <QDialog>
#include <QApplication>
#include <QDesktopWidget>

#include <QDebug>

#include "../components/numpad.h"
#include "../components/smartdelegate.h"
#include "../definitions.h"
#include "../settings.h"
#include "../service.h"


ChequeForm_Touch::ChequeForm_Touch(const QString &params, QWidget *parent) :
    FormInterface(parent)
{
    this->params = params;

    QSettings *userSettings = Settings::getUserInstance();
    QSettings *settings = Settings::getInstance();

    QGridLayout *mainLayout = new QGridLayout(this);

    goodsTable = new QTableWidget(this);
    goodsTable->setColumnCount(8);
    goodsTable->hideColumn(0);
    goodsTable->setSelectionMode(QAbstractItemView::ContiguousSelection);
    goodsTable->setHorizontalHeaderLabels(QStringList()<<"ID"<<"Арт."<<"Товар"<<"-"<<"Кол"<<"+"<<"Цена"<<"Сумма");
    mainLayout->addWidget(goodsTable,0,0);

    // TODO: Перенести в стили
    goodsTable->verticalHeader()->setDefaultSectionSize(settings->value("globals/table_height").toInt());
    goodsTable->setFocusPolicy(Qt::NoFocus);

    connect(goodsTable, SIGNAL(cellClicked(int,int)),this, SLOT(on_goodsTable_cellClicked(int,int)) );


    int size= userSettings->beginReadArray("cheque/preferences/goodsTable");
    for(int i=0;i<size;++i){
        userSettings->setArrayIndex(i);
        goodsTable->setColumnWidth(i, userSettings->value("width",50).toInt());
    }
    userSettings->endArray();

    SmartDelegate *dg = new SmartDelegate(this);
    dg->setReadOnly();

    SmartDelegate *dgsum = new SmartDelegate(this);
    dgsum->setPrecision(2);
    dgsum->setReadOnly();

    SmartDelegate *dgkol = new SmartDelegate(this);
    dg->setReadOnly();

    SmartDelegate *dgd = new SmartDelegate(this);
    dgd->setReadOnly();
    dgd->setAlign(Qt::AlignCenter);

    goodsTable->setItemDelegateForColumn(1, dg);
    goodsTable->setItemDelegateForColumn(2, dg);
    goodsTable->setItemDelegateForColumn(3, dgd);
    goodsTable->setItemDelegateForColumn(4, dgkol);
    goodsTable->setItemDelegateForColumn(5, dgd);
    goodsTable->setItemDelegateForColumn(6, dgsum);
    goodsTable->setItemDelegateForColumn(7, dgsum);

    goodsTable->setMinimumHeight(settings->value("globals/table_height").toInt() * (6));
    goodsTable->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);

    connect(goodsTable, SIGNAL(cellChanged(int,int)), this, SLOT(on_goodsTable_cellChanged(int,int)));
    connect(goodsTable, SIGNAL(currentCellChanged(int,int,int,int)), this, SLOT(on_goodsTable_currentCellChanged(int,int,int,int)));

    QHBoxLayout *goodsTableFooter = new QHBoxLayout();
    mainLayout->addLayout(goodsTableFooter,1,0);


    lastAction  = new QLabel("", this);
    goodsTableFooter->addWidget(lastAction);

    goodsTableFooter->addStretch(1);

    QLabel *lb = new QLabel("Сумма", this);
    goodsTableFooter->addWidget(lb);

    summField = new QLabel("0.00", this);
    goodsTableFooter->addWidget(summField);

    searchModel = new QSqlQueryModel(this);
    searchModel->setQuery(settings->value("queries/cheque/goodslist").toString());

    searchProxy = new SmartSortFilterProxyModel(this);
    searchProxy->setSourceModel(searchModel);
    searchProxy->setFilter("","=2");

    searchTable = new QTableView(this);
    searchTable->setModel(searchProxy);
    searchTable->verticalHeader()->setVisible(false);
    searchTable->verticalHeader()->setDefaultSectionSize(settings->value("globals/table_height").toInt());

    searchTable->hideColumn(0);
    searchProxy->setHeaderData(1, Qt::Horizontal, "Штрихкод");
    searchProxy->setHeaderData(2, Qt::Horizontal, "Арт.");
    searchProxy->setHeaderData(3, Qt::Horizontal, "Название");
    searchProxy->setHeaderData(4, Qt::Horizontal, "Производитель");
    searchProxy->setHeaderData(5, Qt::Horizontal, "Цена");

    searchTable->setItemDelegateForColumn(5, dgsum);

    searchTable->setSelectionMode(QAbstractItemView::SingleSelection);

    connect(searchTable, SIGNAL(clicked(QModelIndex)), this, SLOT(on_searchTable_elementSelected(QModelIndex)));

    mainLayout->addWidget(searchTable,2,0);
    searchTable->hide();

    goodsSelector = new QWidget(this);
    mainLayout->addWidget(goodsSelector,2,0);

    QGridLayout *laGoodsSelector = new QGridLayout();
    goodsSelector->setLayout(laGoodsSelector);


    QSqlQuery groupQuery;
    groupQuery.exec(settings->value("queries/cheque/groupslist").toString());
    int row = 0, column = 0;

    QSignalMapper *signalMapper = new QSignalMapper(this);
    while (groupQuery.next()) {
        int groupid = groupQuery.value(0).toInt();
        QString groupname = groupQuery.value(1).toString();
        if(groupname.length()>10)groupname = groupname.left(9)+"...";

        QPushButton *bt = new QPushButton(groupname, this);
        bt->setMaximumSize(settings->value("globals/button_width").toInt() * 5, settings->value("globals/button_height").toInt());
        bt->setFocusPolicy(Qt::NoFocus);
        laGoodsSelector->addWidget(bt, row, column);

        connect(bt, SIGNAL(clicked()), signalMapper, SLOT(map()));
        signalMapper->setMapping(bt, "group_id="+QString::number(groupid));

        column++; if(column >= settings->value("globals/search_numcolumns").toInt()){row++; column=0;}
    }

    connect(signalMapper, SIGNAL(mapped(QString)),
            this, SLOT(selectGoods(QString)));

    size= userSettings->beginReadArray("cheque/preferences/searchTable");
    for(int i=0;i<size;++i){
        userSettings->setArrayIndex(i);
        searchTable->setColumnWidth(i, userSettings->value("width",50).toInt());
    }
    userSettings->endArray();


    QVBoxLayout *numpadLayout = new QVBoxLayout();

    npad = new Numpad(this);
    npadMode = ChequeForm_Touch::NpadNormalReading;

    connect(npad, SIGNAL(inputChanged(QString)), this, SLOT(on_npad_textChanged(QString)));
    connect(npad, SIGNAL(inputCommited(QString)), this, SLOT(on_npad_textCommited(QString)));

    numpadLayout->addWidget(npad);
    numpadLayout->addStretch(1);

    mainLayout->addLayout(numpadLayout, 0, 1);

    setFocusProxy(npad);

    this->installEventFilter(this);


    QVBoxLayout *buttonsLayout = new QVBoxLayout();
    mainLayout->addLayout(buttonsLayout, 2, 1);
    buttonsLayout->setContentsMargins(settings->value("globals/button_width").toInt(),0,0,0);

    QPushButton *btReconnect = new QPushButton("Обн.устр",this);
    btReconnect->setMaximumSize(settings->value("globals/button_width").toInt() * 2 + settings->value("globals/button_hmargin").toInt(), settings->value("globals/button_height").toInt());
    btReconnect->setMinimumSize(settings->value("globals/button_width").toInt() * 2 + settings->value("globals/button_hmargin").toInt(), settings->value("globals/button_height").toInt());
    btReconnect->setFocusPolicy(Qt::NoFocus);
    buttonsLayout->addWidget(btReconnect);
    connect(btReconnect, SIGNAL(clicked()), this, SLOT(reconnectDevices()));


    QPushButton *btCommit = new QPushButton("Пробить",this);
    btCommit->setMaximumSize(settings->value("globals/button_width").toInt() * 2 + settings->value("globals/button_hmargin").toInt(), settings->value("globals/button_height").toInt());
    btCommit->setMinimumSize(settings->value("globals/button_width").toInt() * 2 + settings->value("globals/button_hmargin").toInt(), settings->value("globals/button_height").toInt());
    btCommit->setFocusPolicy(Qt::NoFocus);

    buttonsLayout->addStretch(1);
    buttonsLayout->addWidget(btCommit);

    connect(btCommit, SIGNAL(clicked()), this, SLOT(on_btCommit_clicked()));

    serial = 0; // init
    reconnectDevices();

}

ChequeForm_Touch::~ChequeForm_Touch()
{
    QSettings *userSettings = Settings::getUserInstance();

    userSettings->beginWriteArray("cheque/preferences/goodsTable");
    for(int i=0;i<goodsTable->columnCount();++i){
        userSettings->setArrayIndex(i);
        userSettings->setValue("width", goodsTable->columnWidth(i));
    }
    userSettings->endArray();

    userSettings->beginWriteArray("cheque/preferences/searchTable");
    for(int i=0;i<searchModel->columnCount();++i){
        userSettings->setArrayIndex(i);
        userSettings->setValue("width", searchTable->columnWidth(i));
    }
    userSettings->endArray();
}


bool ChequeForm_Touch::eventFilter(QObject *obj, QEvent *event)
{
    if (event->type() == QEvent::KeyPress) {
        QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);

        if(keyEvent->key()==Qt::Key_F11){
            npad->clearText();
            npad->setModeLabel("");
            npad->setFocus(Qt::OtherFocusReason);
            npadMode = ChequeForm_Touch::NpadBarcodeReading;
            return true;
        }
        /*
        if(keyEvent->key()==Qt::Key_Return&&!ui->leBarcode->text().isEmpty()){
            QString str = ui->leBarcode->text();
            ui->leBarcode->setText("");
            return true;
        }

        if(keyEvent->key()==Qt::Key_F9){
            ui->leMoney->setText("");
            ui->leMoney->setFocus(Qt::OtherFocusReason);
            return true;
        }

*/
    }

    return QWidget::eventFilter(obj, event);
}


void ChequeForm_Touch::addGoods(int GOODS_ID, double kol_add)
{
    bool is_new = true;
    for (int i = 0; i < goodsTable->rowCount() && is_new; ++i)
    {
        if(goodsTable->item(i, 0)->data(Qt::DisplayRole)==GOODS_ID)
        {
            is_new    = false;
            goodsTable->item(i,4)->setData(Qt::DisplayRole, QString::number(kol_add + goodsTable->item(i, 4)->data(Qt::DisplayRole).toDouble()));
            goodsTable->selectRow(i);

            lastAction->setText("+"+QString::number(kol_add)+" х "+(goodsTable->item(i,1)->data(Qt::DisplayRole).toString())+" "+(goodsTable->item(i,2)->data(Qt::DisplayRole).toString()));
        }
    }

    if(is_new)
    {
        QSqlQuery que;
        que.prepare(Settings::getInstance()->value("queries/cheque/search_goods_by_id").toString());
        que.bindValue(":val",GOODS_ID);
        que.exec();

        if(!que.next())return;

        int nrow = goodsTable->rowCount();

        goodsTable->insertRow(nrow);
        goodsTable->setItem(nrow,0,new QTableWidgetItem(QString::number(GOODS_ID)));
        goodsTable->setItem(nrow,1,new QTableWidgetItem(que.value(0).toString()));
        goodsTable->setItem(nrow,2,new QTableWidgetItem(que.value(1).toString()));
        // обратный порядок чтобы при вставке кол-ва уже был итем суммы и чтобы она автоматом посчиталась
        goodsTable->setItem(nrow,7,new QTableWidgetItem("0"));
        goodsTable->setItem(nrow,6,new QTableWidgetItem(QString::number(que.value(2).toDouble(), 'f', 2)));
        goodsTable->setItem(nrow,4,new QTableWidgetItem(QString::number(kol_add)));

        goodsTable->setItem(nrow,5,new QTableWidgetItem("+"));
        goodsTable->setItem(nrow,3,new QTableWidgetItem("-"));
        goodsTable->selectRow(nrow);

        lastAction->setText(QString::number(kol_add)+" х "+(que.value(0).toString())+" "+(que.value(1).toString()));
    }

    addSumm(0);
}


void ChequeForm_Touch::addSumm(double summ_add){
    double sum = summField->text().toDouble()+summ_add;
    summField->setText(QString::number(sum, 'f', 2));
    //on_leMoney_textChanged(ui->leMoney->text());
}

void ChequeForm_Touch::on_goodsTable_currentCellChanged(int,int,int,int){
    if (npadMode==ChequeForm_Touch::NpadQtyReading || npadMode==ChequeForm_Touch::NpadPriceReading){
        npadMode=ChequeForm_Touch::NpadNormalReading;
        npad->setModeLabel("");
        npad->clearText();
        npad->setFocus(Qt::OtherFocusReason);
    }
}

void ChequeForm_Touch::on_goodsTable_cellChanged(int row, int column)
{
    if(column==4 || column==6)
    {
        QTableWidgetItem *isumm  = goodsTable->item(row,7);
        QTableWidgetItem *iprice    = goodsTable->item(row,6);
        QTableWidgetItem *ikol       = goodsTable->item(row,4);
        if(!ikol || !iprice || !isumm)
            return;

        double before = Service::round(isumm->data(Qt::DisplayRole).toDouble(),2);
        double after   = Service::round(ikol->data(Qt::DisplayRole).toDouble() * iprice->data(Qt::DisplayRole).toDouble(),2);

        addSumm(after-before);

        if(after!=before)
            isumm->setText(QString::number(after, 'f', 2));

        lastAction->setText(" * "+(goodsTable->item(row,1)->data(Qt::DisplayRole).toString())+" "+(goodsTable->item(row,2)->data(Qt::DisplayRole).toString()));

    }

}

void ChequeForm_Touch::on_goodsTable_cellClicked(int row, int column)
{
    if(column==3 || column==5)
    {
        QTableWidgetItem *ikol       = goodsTable->item(row,4);
        if(!ikol)
            return;

        int delta = column==3?-1:1;

        if(ikol->data(Qt::DisplayRole).toDouble() + delta<=0){
            // kill
            QTableWidgetItem *isumm       = goodsTable->item(row,7);
            addSumm(-isumm->data(Qt::DisplayRole).toDouble());
            lastAction->setText(" - "+(goodsTable->item(row,1)->data(Qt::DisplayRole).toString())+" "+(goodsTable->item(row,2)->data(Qt::DisplayRole).toString()));
            goodsTable->removeRow(row);
        }else
            // correct. here will be normal
            ikol->setText(QString::number(ikol->data(Qt::DisplayRole).toDouble() + delta));

    }

    if (column == 4) {
        npadMode = ChequeForm_Touch::NpadQtyReading;
        npad->setModeLabel("Кол:");
        npad->clearText();
        npad->setFocus(Qt::OtherFocusReason);
    }
    if (column == 6) {
        npadMode = ChequeForm_Touch::NpadPriceReading;
        npad->setModeLabel("Цена:");
        npad->clearText();
        npad->setFocus(Qt::OtherFocusReason);
    }


}


void ChequeForm_Touch::on_npad_textChanged(const QString& text)
{
    if(text.length()>0){
        goodsSelector->hide();
        searchTable->show();
    }else{
        goodsSelector->show();
        searchTable->hide();
    }


    if(npadMode==ChequeForm_Touch::NpadNormalReading){
        if(text.length()>6)
            searchProxy->setFilter(text,"1,2");
        else
            searchProxy->setFilter(text,"=2");
    }
}

void ChequeForm_Touch::on_npad_textCommited(const QString& text)
{
    if(npadMode==ChequeForm_Touch::NpadNormalReading){
        addGoods(searchProxy->getValue(0,0).toInt(),1.0);
    }

    // 40822426
    if(npadMode==ChequeForm_Touch::NpadBarcodeReading){

        QSqlQuery que;
        que.prepare(Settings::getInstance()->value("queries/globals/search_by_barcode").toString());
        que.bindValue(":val", text);

        if(que.next()){
            addGoods(que.value(0).toInt(),1.0);
        }else{
            lastAction->setText("Ошибка поиска штрихкода "+text);
            npad->clearText();
            npad->setFocus(Qt::OtherFocusReason);
        }
    }


    if(npadMode==ChequeForm_Touch::NpadQtyReading){
        QTableWidgetItem *ikol       = goodsTable->item(goodsTable->currentRow(),4);
        ikol->setText(text);
    }

    if(npadMode==ChequeForm_Touch::NpadPriceReading){
        QTableWidgetItem *iprc       = goodsTable->item(goodsTable->currentRow(),6);
        iprc->setText(text);
    }


    npadMode = ChequeForm_Touch::NpadNormalReading;
    npad->setModeLabel("");
}


void ChequeForm_Touch::on_searchTable_elementSelected(QModelIndex mi)
{
    addGoods(searchProxy->getValue(mi.row(),0).toInt(),1.0);
    npad->clearText();
    npad->setFocus(Qt::OtherFocusReason);
    npadMode = ChequeForm_Touch::NpadNormalReading;
}

void ChequeForm_Touch::on_barcode_readyRead()
{
    QByteArray barcode = serial->readAll();
    while (serial->waitForReadyRead(10))
        barcode += serial->readAll();
    barcode = barcode.simplified();

    QSqlQuery que;
    que.prepare(Settings::getInstance()->value("queries/globals/search_by_barcode").toString());
    que.bindValue(":val", barcode);

    if(que.next()){
        addGoods(que.value(0).toInt(),1.0);
    }else{
        lastAction->setText("Ошибка поиска штрихкода "+barcode);
        npad->clearText();
        npad->setFocus(Qt::OtherFocusReason);
    }
}


void ChequeForm_Touch::selectGoods(const QString &params){
    QDialog *dlg = new QDialog();

    QSettings *settings = Settings::getInstance();

    QSqlQueryModel *searchModel = new QSqlQueryModel(dlg);
    QString query = settings->value("queries/cheque/groupslist_with_params_preffics").toString();
    if (!params.isEmpty())
        query += " "+settings->value("queries/cheque/groupslist_with_params_where").toString() +" "+params;
    query += QString(" ")+settings->value("queries/cheque/groupslist_with_params_suffics").toString();

    searchModel->setQuery(query);

    QTableView *searchTable = new QTableView(dlg);
    searchTable->setModel(searchModel);
    searchTable->verticalHeader()->setVisible(false);
    searchTable->verticalHeader()->setDefaultSectionSize(settings->value("globals/table_height").toInt());

    searchTable->hideColumn(0);
    searchModel->setHeaderData(1, Qt::Horizontal, "Арт.");
    searchModel->setHeaderData(2, Qt::Horizontal, "Название");
    searchModel->setHeaderData(3, Qt::Horizontal, "Цена");

    SmartDelegate *dgsum = new SmartDelegate(this);
    dgsum->setPrecision(2);
    dgsum->setReadOnly();
    searchTable->setItemDelegateForColumn(3, dgsum);

    QHBoxLayout *la = new  QHBoxLayout(dlg);
    la->addWidget(searchTable);

    connect(searchTable, SIGNAL(clicked(QModelIndex)), dlg, SLOT(accept()));

    QSettings *userSettings = Settings::getUserInstance();

    int size= userSettings->beginReadArray("cheque/preferences/selectordialog/table");
    for(int i=0;i<size;++i){
        userSettings->setArrayIndex(i);
        searchTable->setColumnWidth(i, userSettings->value("width",50).toInt());
    }
    userSettings->endArray();

    //QScreen scr;

    QRect geometry = QApplication::desktop()->screenGeometry();
    dlg->setMinimumSize(geometry.width(), geometry.height());//settings->value("cheque/preferences/selectordialog/width",800).toInt(), settings->value("cheque/preferences/selectordialog/height",600).toInt());

    if (dlg->exec()){
        QModelIndex mi = searchTable->currentIndex();
        mi = mi.sibling(mi.row(), 0);
        addGoods(searchModel->data(mi).toInt(),1.0);
    }

    userSettings->setValue("cheque/preferences/selectordialog/width", dlg->size().width());
    userSettings->setValue("cheque/preferences/selectordialog/height", dlg->size().height());

    userSettings->beginWriteArray("cheque/preferences/selectordialog/table");
    for(int i=0;i<searchModel->columnCount();++i){
        userSettings->setArrayIndex(i);
        userSettings->setValue("width", searchTable->columnWidth(i));
    }
    userSettings->endArray();

    delete dlg;
}

void ChequeForm_Touch::on_btCommit_clicked()
{
    QSqlDatabase db = QSqlDatabase::database();
    db.transaction();

    QSqlQuery query(db);

    QSettings *settings = Settings::getInstance();

    if(!query.exec(settings->value("queries/cheque/get_new_document_id").toString())){
        db.rollback();
        qDebug()<<posInFile<<query.lastError().text()<<endl<<query.lastQuery()<<endl<<query.boundValues();
        return;
    }

    query.next();
    int doc_id = query.value(0).toInt();


    if(params.contains("cheque for return")){
        query.prepare(settings->value("queries/cheque/save_cheque_for_return").toString());
    }else{
        query.prepare(settings->value("queries/cheque/save_cheque").toString());
    }

    query.bindValue(":id", doc_id);
    query.bindValue(":ndoc", QString::number(doc_id));
    query.bindValue(":data", QDate::currentDate());
    query.bindValue(":store", Settings::getDefinition("ТЕКУЩАЯ_БАЗА").toInt());
    query.bindValue(":user", Settings::getVariables()->value("user_id").toInt());

    if(!query.exec()){
        db.rollback();
        qDebug()<<posInFile<<query.lastError().text()<<endl<<query.lastQuery()<<endl<<query.boundValues();
        return;
    }


    for (int i = 0; i < goodsTable->rowCount(); ++i) {
        if(!query.exec(settings->value("queries/cheque/get_new_document_pos_id").toString())){
            db.rollback();
            qDebug()<<posInFile<<query.lastError().text()<<endl<<query.lastQuery()<<endl<<query.boundValues();
            return;
        }

        query.next();
        int dgoods_id = query.value(0).toInt();


        query.prepare(settings->value("queries/cheque/save_document_pos").toString());

        query.bindValue(":id",dgoods_id);
        query.bindValue(":document_id",doc_id);

        query.bindValue(":goods_id",goodsTable->item(i,0)->data(Qt::DisplayRole).toInt());
        query.bindValue(":kol",goodsTable->item(i,4)->data(Qt::DisplayRole).toDouble());
        query.bindValue(":price",goodsTable->item(i,6)->data(Qt::DisplayRole).toDouble());
        query.bindValue(":summ",goodsTable->item(i,7)->data(Qt::DisplayRole).toDouble());

        if(!query.exec()){
            db.rollback();
            qDebug()<<posInFile<<query.lastError().text()<<endl<<query.lastQuery()<<endl<<query.boundValues();
            return;
        }
    }

    db.commit();

    Service::printCheque(doc_id);

    npad->clearText();
    npad->setFocus(Qt::OtherFocusReason);

    for(int i=goodsTable->rowCount(); i>0;--i)
        goodsTable->removeRow(i-1);
    summField->setText(QString::number(0, 'f', 2));

    lastAction->setText("Чек №"+QString::number(doc_id)+" сохранен");

    emit chequeCommited();
}


void ChequeForm_Touch::reconnectDevices(){
    QSettings *settings = Settings::getInstance();
    if (settings->value("devices/comportscanner/is_enabled").toBool()==true){
        QString dev = settings->value("devices/comportscanner/device").toString();
        if (!serial)
            serial = new QSerialPort(this);
        else
            serial->close();

        serial->setPortName(dev);
        if (serial->open(QIODevice::ReadOnly)){
            serial->setStopBits((QSerialPort::StopBits)settings->value("devices/comportscanner/stopbits").toInt()); // 1-1 stop bit, 3-1.5 stop bits, 2-2 stop bits
            serial->setDataBits((QSerialPort::DataBits)settings->value("devices/comportscanner/databits").toInt()); // 5-8
            serial->setParity((QSerialPort::Parity)settings->value("devices/comportscanner/parity").toInt()); // 0-No parity, 2-Even parity, 3-Odd parity,4-Space parity, 5-Mark parity.
            serial->setBaudRate((QSerialPort::BaudRate)settings->value("devices/comportscanner/baudrate").toInt());  // 1200,  2400, 4800, 9600, 19200...

            connect(serial, SIGNAL(readyRead()), this, SLOT(on_barcode_readyRead()));
        }
    }
}
